using System;
using System.Collections.Generic;
using NUnit.Framework;
using Microsoft.Build.BuildEngine;
using System.Runtime.InteropServices;

namespace Fines.Powershell.PowershellMSBuildTask.Tests
{
    [TestFixture]
    public class EngineTests
    {
        private Engine engine;
        private TestLogger logger;
        private Project project;

        [SetUp]
        public void SetUp()
        {
            this.engine = new Engine( RuntimeEnvironment.GetRuntimeDirectory() );
            this.logger = new TestLogger();
            this.project = new Project( this.engine );
            this.project.Load( "BuildFile.proj" );

            this.engine.RegisterLogger( this.logger );
        }

        [TearDown]
        public void TearDown()
        {
           
        }

        [Test]
        public void HelloWorld()
        {

            bool res = this.project.Build( "HelloWorld" );

            this.AssertNoErrors();

            AssertIsInLogger( "PSOutput:Hello world", this.logger.Messages );

            Assert.IsTrue( res );
        }

        [Test]
        public void TaskItems()
        {
            this.project.Build( "TaskItems" );
            this.AssertNoErrors();
            AssertIsInLogger( "PSOutput:The answer is 42", this.logger.Messages );
        }

        [Test]
        public void WriteHost()
        {
            this.project.Build( "WriteHost" );
            this.AssertNoErrors();
            AssertIsInLogger( "Writing to host", this.logger.Messages );
        }

        [Test]
        public void WriteWarning()
        {
            this.project.Build( "WriteWarning" );
            this.AssertNoErrors();
            AssertIsInLogger( "Writing to warning", this.logger.Warnings );
        }

        [Test]
        public void WriteVerbose()
        {
            this.project.Build( "WriteVerbose" );
            this.AssertNoErrors();
            AssertIsInLogger( "Writing to verbose", this.logger.Messages );
        }

        [Test]
        public void WriteError()
        {
            this.project.Build( "WriteError" );
            AssertIsInLogger( "Writing to error", this.logger.Errors );
        }

        [Test]
        public void PreferenceVariables()
        {
            this.project.Build( "PreferenceVariables" );
            AssertIsInLogger( "VerbosePreference: Stop", this.logger.Messages );
            AssertIsInLogger( "DebugPreference: Continue", this.logger.Messages );
            AssertIsInLogger( "ShouldProcessPreference: Stop", this.logger.Messages );
            AssertIsInLogger( "ErrorActionPreference: Continue", this.logger.Messages );
            AssertIsInLogger( "ProcessReturnPreference: True", this.logger.Messages );
        }

        [Test]
        public void Arguments()
        {
            this.project.Build( "Arguments" );
            AssertNoErrors();
            AssertIsInLogger( "Foo is Bar, Baz is Bat", this.logger.Messages );
        }

        [Test]
        public void ComplexArguments()
        {
            this.project.Build("ComplexArguments");
            AssertNoErrors();
            AssertIsInLogger("Foo is 1+1=2, Baz is 2*2=4", this.logger.Messages);
        }

        [Test]
        public void ExternalScript()
        {
            this.project.Build("ExternalScriptFile");
            AssertNoErrors();
            AssertIsInLogger("Hello", this.logger.Messages);
            AssertIsInLogger("World", this.logger.Messages);
        }
        

        private static void AssertIsInLogger( string p, IEnumerable<string> messages )
        {
            string messageString = "";
            foreach ( string message in messages )
            {
                if ( message == p )
                {
                    return;
                }
                messageString += message + Environment.NewLine;
            }
            Assert.Fail( "Message '{0}' not found in logger output, this is what was found instead: {1}", p, messageString );
        }

        private void AssertNoErrors()
        {
            if ( this.logger.Errors.Count == 0 )
            {
                return;
            }

            string messages = "";
            foreach ( string s in this.logger.Errors )
            {
                messages += s + Environment.NewLine;
            }

            Assert.Fail( messages );
        }

        
    }
}
